package net.chasing.androidbaseconfig.util;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.media.MediaMetadataRetriever;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.text.TextUtils;
import android.util.Base64;
import android.view.View;

import androidx.annotation.RequiresApi;
import androidx.core.content.FileProvider;
import androidx.fragment.app.FragmentActivity;

import net.chasing.androidbaseconfig.R;
import net.chasing.androidbaseconfig.util.permission.PermissionUtils;
import net.chasing.androidbaseconfig.util.thread.ComparableRunnable;
import net.chasing.androidbaseconfig.util.thread.ThreadPoolUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.Objects;

public class FileUtils {
    //默认压缩精度
    private static final int NORMAL_QUALITY = 80;

    private static String getLastAppName(Context context) {
        String[] appName = context.getPackageName().split("\\.");
        return appName[appName.length - 1];
    }

    public static String getFileProvider(Context context) {
        String provider = context.getPackageName() + ".fileprovider";
        L.i(provider);
        return provider;
    }

    public static boolean isBelow29() {
        // 使用Environment.isExternalStorageLegacy()来检查APP的运行模式
        return Build.VERSION.SDK_INT < Build.VERSION_CODES.Q ||
                Environment.isExternalStorageLegacy();
    }

    public static boolean isFilePath(String path) {
        if (TextUtils.isEmpty(path)) return false;
        return path.startsWith("file://") || path.startsWith("/storage/emulated/0")
                || path.startsWith("/data/user/0");
    }

    public static boolean isSelfFile(Context context, String path) {
        return path.contains(context.getFilesDir().getPath()) ||
                path.contains(context.getCacheDir().getPath());
    }

    // 使用时使用子线程判断 单次可能还没什么影响，列表类型的会明显卡顿
    public static boolean exists(Context context, String path) {
        if (context == null) return false;
        if (TextUtils.isEmpty(path)) return false;
        else if (isBelow29()) {
            File file = new File(path);
            return file.exists();
        } else {
            AssetFileDescriptor afd = null;
            ContentResolver cr = context.getContentResolver();
            try {
                Uri uri = getFileUri(context, path);
                if (uri == null) return false;
                afd = cr.openAssetFileDescriptor(uri, "r");
                if (afd == null) return false;
            } catch (FileNotFoundException e) {
                return false;
            } finally {
                if (afd != null) {
                    try {
                        afd.close();
                    } catch (Exception ignored) {
                    }
                }
            }
            return true;
        }
    }

    // 判断私有目录是否存在，不存在则进行创建
    private static void createSelfDirIfNotExist(String path) {
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    public static void deleteFile(String filePath) {
        if (TextUtils.isEmpty(filePath)) return;
        try {
            File file = new File(filePath);
            if (file.exists() && file.isFile()) {
                file.delete();
            }
        } catch (Exception ignored) {
        }
    }

    // 递归删除目录下的所有文件及子目录下所有文件
    public static void deleteDir(String dirPath) {
        if (TextUtils.isEmpty(dirPath)) return;
        deleteDir(new File(dirPath));
    }

    private static void deleteDir(File dir) {
        try {
            if (null == dir || !dir.exists() || !dir.isDirectory() || dir.listFiles() == null) {
                return;
            }
            for (File file : Objects.requireNonNull(dir.listFiles())) {
                if (file.isFile())
                    try {
                        file.delete(); // 删除所有文件
                    } catch (Exception ignored) {
                    }
                else if (file.isDirectory())
                    deleteDir(file); // 递规的方式删除文件夹
            }
            try {
                dir.delete(); //此时目录为空，可以删除
            } catch (Exception ignored) {
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 每次启动应用删除overTime时间前未发送成功的聊天图片及拍照图片
    public static void deleteOverTimeSelfFile(File file, long overTime) {
        if (file == null) return;
        try {
            if (file.exists() && file.isDirectory() && file.listFiles() != null) {
                for (File subFile : Objects.requireNonNull(file.listFiles())) {
                    if (subFile.isFile()) {
                        long lastModifyTime = subFile.lastModified();
                        if (System.currentTimeMillis() - lastModifyTime >= overTime)
                            subFile.delete();
                    }
                }
            }
        } catch (Exception ignored) {
        }
    }

    private static String getSystemRootPath(String directory) {
        String pictures = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
                + File.separator + directory + File.separator;
        File file = new File(pictures);
        if (!file.exists())
            file.mkdirs();
        return pictures;
    }

    public static String getDownloadPath() {
        return getSystemRootPath(Environment.DIRECTORY_DOWNLOADS);
    }

    // 获取app的私有目录路径
    public static String getAppFilePath(Context context, String directory) {
        String filePath = context.getFilesDir().getPath() + File.separator + directory + File.separator;
        createSelfDirIfNotExist(filePath);
        return filePath;
    }

    // 获取缓存路径
    public static String getAppCachePath(Context context, String directory) {
        String filePath;
        if (TextUtils.isEmpty(directory))
            filePath = context.getCacheDir().getPath() + File.separator;
        else
            filePath = context.getCacheDir().getPath() + File.separator + directory + File.separator;
        createSelfDirIfNotExist(filePath);
        return filePath;
    }

    public static String getExternalAppCachePath(Context context, String directory) {
        File externalCacheDir = context.getExternalCacheDir();
        if (externalCacheDir == null)
            externalCacheDir = context.getCacheDir();
        String filePath;
        if (TextUtils.isEmpty(directory))
            filePath = externalCacheDir.getPath() + File.separator;
        else
            filePath = externalCacheDir.getPath() + File.separator + directory + File.separator;
        createSelfDirIfNotExist(filePath);
        return filePath;
    }

    // name需要后缀  android 10 之后下载文件到公共目录需要使用uri：
    public static Uri getDownloadPicUri(Context context, String imageName) {
        String mimeType = FileTypeUtils.getMIMEType(imageName);
        if (!mimeType.startsWith("image")) {
            if (mimeType.startsWith("video"))
                return getDownloadVideoUri(context, imageName);
            else
                return getDownloadDocumentUri(context, imageName);
        }

        imageName = RegexUtils.replaceChineseSymbol(imageName);
        imageName = TimeUtils.long2String(System.currentTimeMillis(), "yyyyMMddHHmmss-") + imageName;

        //设置保存参数到ContentValues中
        ContentValues contentValues = new ContentValues();
        //设置文件名
        contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, imageName);
        //兼容Android Q和以下版本
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            //android Q中不再使用DATA字段，而用RELATIVE_PATH代替
            //RELATIVE_PATH是相对路径不是绝对路径
            //DCIM是系统文件夹，关于系统文件夹可以到系统自带的文件管理器中查看，不可以写没存在的名字
            contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES +
                    File.separator + getLastAppName(context));
            contentValues.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
        } else {
            //Android Q以下版本
            File fileDir = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES +
                    File.separator + getLastAppName(context));
            if (!fileDir.exists()) {
                fileDir.mkdir();
            }
            String filePath = FileUtils.judgeFilePathExist(context, fileDir.getAbsolutePath() + "/" + imageName);
            contentValues.put(MediaStore.Images.Media.DATA, filePath);
        }
        //设置文件类型
//        contentValues.put(MediaStore.Images.Media.MIME_TYPE, mimeType);
        //获取不到正确的文件类型
        contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/*");
        //执行insert操作，向系统文件夹中添加文件
        //EXTERNAL_CONTENT_URI代表外部存储器，该值不变
        return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
    }

    @SuppressLint("DefaultLocale")
    public static Uri getDownloadDocumentUri(Context context, String fileName) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            fileName = RegexUtils.replaceChineseSymbol(fileName);
            fileName = TimeUtils.long2String(System.currentTimeMillis(), "yyyyMMddHHmmss-") + fileName;

            //设置保存参数到ContentValues中
            ContentValues contentValues = new ContentValues();
            //设置文件名
            contentValues.put(MediaStore.Downloads.DISPLAY_NAME, fileName);
            //RELATIVE_PATH是相对路径不是绝对路径
            //Download是系统文件夹，关于系统文件夹可以到系统自带的文件管理器中查看，不可以写没存在的名字
            contentValues.put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS +
                    File.separator + getLastAppName(context));
            contentValues.put(MediaStore.Downloads.DATE_TAKEN, System.currentTimeMillis());
            //设置文件类型
            contentValues.put(MediaStore.Downloads.MIME_TYPE, FileTypeUtils.getMIMEType(fileName));
            //执行insert操作，向系统文件夹中添加文件
            //EXTERNAL_CONTENT_URI代表外部存储器，该值不变
            return context.getContentResolver().insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues);
        } else {
            return getFileUri(context, getDownloadPath() + fileName);
        }
    }

    public static Uri getDownloadVideoUri(Context context, String videoName) {
        String mimeType = FileTypeUtils.getMIMEType(videoName);
        if (!mimeType.startsWith("video")) {
            if (mimeType.startsWith("image"))
                return getDownloadPicUri(context, videoName);
            else
                return getDownloadDocumentUri(context, videoName);
        }

        videoName = RegexUtils.replaceChineseSymbol(videoName);
        videoName = TimeUtils.long2String(System.currentTimeMillis(), "yyyyMMddHHmmss-") + videoName;

        //设置保存参数到ContentValues中
        ContentValues contentValues = new ContentValues();
        //设置文件名
        contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, videoName);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            //android Q中不再使用DATA字段，而用RELATIVE_PATH代替
            //RELATIVE_PATH是相对路径不是绝对路径
            //DCIM是系统文件夹，关于系统文件夹可以到系统自带的文件管理器中查看，不可以写没存在的名字
            contentValues.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_MOVIES +
                    File.separator + getLastAppName(context));
            contentValues.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());
        } else {
            //Android Q以下版本
            File fileDir = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_MOVIES +
                    File.separator + getLastAppName(context));
            if (!fileDir.exists()) {
                fileDir.mkdir();
            }
            String path = FileUtils.judgeFilePathExist(context, fileDir.getAbsolutePath() + "/" + videoName);
            contentValues.put(MediaStore.Video.Media.DATA, path);
        }
        //设置文件类型
        contentValues.put(MediaStore.Video.Media.MIME_TYPE, "video/*");
        //执行insert操作，向系统文件夹中添加文件
        //EXTERNAL_CONTENT_URI代表外部存储器，该值不变
        return context.getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValues);
    }

    public static Uri getDownloadAudioUri(Context context, String audioName) {
        String mimeType = FileTypeUtils.getMIMEType(audioName);
        if (!mimeType.startsWith("audio")) {
            if (mimeType.startsWith("image"))
                return getDownloadPicUri(context, audioName);
            else if (mimeType.startsWith("video"))
                return getDownloadVideoUri(context, audioName);
            else
                return getDownloadDocumentUri(context, audioName);
        }

        audioName = RegexUtils.replaceChineseSymbol(audioName);
        audioName = TimeUtils.long2String(System.currentTimeMillis(), "yyyyMMddHHmmss-") + audioName;

        //设置保存参数到ContentValues中
        ContentValues contentValues = new ContentValues();
        //设置文件名
        contentValues.put(MediaStore.Audio.Media.DISPLAY_NAME, audioName);
        //兼容Android Q和以下版本
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            //android Q中不再使用DATA字段，而用RELATIVE_PATH代替
            //RELATIVE_PATH是相对路径不是绝对路径
            //DCIM是系统文件夹，关于系统文件夹可以到系统自带的文件管理器中查看，不可以写没存在的名字
            contentValues.put(MediaStore.Audio.Media.RELATIVE_PATH, Environment.DIRECTORY_MUSIC +
                    File.separator + getLastAppName(context));
            contentValues.put(MediaStore.Audio.Media.DATE_TAKEN, System.currentTimeMillis());
        } else {
            //Android Q以下版本
            File fileDir = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_MUSIC +
                    File.separator + getLastAppName(context));
            if (!fileDir.exists()) {
                fileDir.mkdir();
            }
            String suffix = audioName.substring(audioName.lastIndexOf("."));
            String filePath = fileDir.getAbsolutePath() + "/" + System.currentTimeMillis() + suffix;
//            String filePath = FileUtils.judgeFilePathExist(context, fileDir.getAbsolutePath() + "/" + audioName);
            contentValues.put(MediaStore.Audio.Media.DATA, filePath);
        }
        //设置文件类型
//        contentValues.put(MediaStore.Audio.Media.MIME_TYPE, mimeType);
        contentValues.put(MediaStore.Audio.Media.MIME_TYPE, "audio/*");
        //执行insert操作，向系统文件夹中添加文件
        //EXTERNAL_CONTENT_URI代表外部存储器，该值不变
        return context.getContentResolver().insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, contentValues);
    }

    @TargetApi(Build.VERSION_CODES.Q)
    public static void deleteDownloadDocument(Context context, String fileName) {
        context.getContentResolver().delete(MediaStore.Downloads.EXTERNAL_CONTENT_URI,
                MediaStore.Downloads.DISPLAY_NAME + "='" + fileName + "'", null);
    }

    // 获取临时缓存目录
    public static String getTempPath(Context context) {
        String tempPath = getAppFilePath(context, "temp");
        createSelfDirIfNotExist(tempPath);
        return tempPath;
    }

    // 获取log存储路径
    public static String getLogPath(Context context) {
        return getAppFilePath(context, "log");
    }

    // 视频第一帧图片的存放位置  注：每七天清理一次
    static String getVideoThumbnailPath(Context context) {
        return getAppFilePath(context, "thumbnail");
    }

    /**
     * 每次启动应用
     * 删除7天前的视频第一帧的缓存
     * 删除3天前file/temp/下的缓存文件
     * 删除3天前cache/下的缓存文件
     */
    public static void deleteOverTimeTempFile(Context context) {
        deleteOverTimeSelfFile(new File(getVideoThumbnailPath(context)), 7 * 24 * 60 * 60 * 1000);
        deleteOverTimeSelfFile(new File(getTempPath(context)), 3 * 24 * 60 * 60 * 1000);
        deleteOverTimeSelfFile(new File(getAppCachePath(context, null)), 3 * 24 * 60 * 60 * 1000);
    }

    // 文件保存删除后，调用媒体库数据更新（图片才能显示到相册里面或从相册里面删除），filePath是文件路径全名，包括后缀哦
    public static void updateGallery(Context context, String filePath) {
        MediaScannerConnection.scanFile(context,
                new String[]{filePath}, null,
                (path, uri) -> context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
                        Uri.fromFile(new File(filePath)))));
    }

    // 判断文件路径对应的文件是否存在，如果存在则通过加"(1)"的形式进行重新创建一个文件不存在的路径进行返回
    @SuppressLint("DefaultLocale")
    public static String judgeFilePathExist(Context context, String filePath) {
        if (FileUtils.exists(context, filePath)) {
            if (filePath.contains("(") && filePath.contains(")") &&
                    filePath.lastIndexOf(")") > filePath.lastIndexOf("(")) {
                String number = filePath.substring(filePath.lastIndexOf("(") + 1, filePath.lastIndexOf(")"));
                try {
                    int integer = Integer.parseInt(number);
                    integer++;
                    for (; integer > 0; integer++) {
                        filePath = String.format("%s%s%s", filePath.substring(0, filePath.lastIndexOf("(") + 1), integer, filePath.substring(filePath.lastIndexOf(")")));
                        if (!FileUtils.exists(context, filePath))
                            break;
                    }
                } catch (NumberFormatException e) {
                    filePath = String.format("%s%s%s", filePath.substring(0, filePath.lastIndexOf(".")), "(1)", filePath.substring(filePath.lastIndexOf(".")));
                }
            } else {
                String temp;
                int i = 1;
                while (i > 0) {
                    temp = String.format("%s%s%s", filePath.substring(0, filePath.lastIndexOf(".")), String.format("(%d)", i), filePath.substring(filePath.lastIndexOf(".")));
                    if (!FileUtils.exists(context, temp)) {
                        filePath = temp;
                        break;
                    }
                    i++;
                }
            }
        }
        return filePath;
    }

    /**
     * 打开文件
     *
     * @param filePath 文件路径
     */
    public static void openFile(Context context, String filePath) {
        if (!exists(context, filePath)) {
            //如果文件不存在
            ToastUtils.showShort(context, R.string.base_open_file_fail);
        } else {
            try {
                Uri fileUri = FileUtils.getFileUri(context, filePath);
                if (fileUri != null) {
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                    intent.addCategory("android.intent.category.DEFAULT");
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    intent.setDataAndType(fileUri, FileTypeUtils.getMIMEType(filePath));
                    context.startActivity(intent);
                }
            } catch (Exception e) {
                ToastUtils.showShort(context, R.string.base_uncheck_app_for_enable_open_this_file);
            }
        }
    }

    // 根据路径得到该本地文件的长度(Byte)
    public static long getFileLength(String path) {
        if (TextUtils.isEmpty(path)) return 0;
        return new File(path).length();
    }

    public static long getFileLength(Context context, Uri uri) {
        if (context == null || uri == null) return 0;
        Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
        long length = 0;
        if (cursor != null && cursor.moveToFirst()) {
            int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
            if (!cursor.isNull(sizeIndex)) {
                length = cursor.getLong(sizeIndex);
            }
        }
        if (cursor != null)
            cursor.close();
        return length;
    }

    public static long getFileLength(Context context, Uri uri, String filePath) {
        long length = getFileLength(context, uri);
        if (length == 0)
            length = getFileLength(filePath);
        return length;
    }

    // 将单位为B的length转换成KB/MB/GB，并添加单位一起返回
    @SuppressLint("DefaultLocale")
    public static String getShortFileLength(long length) {
        if (length >= 1024) {
            float shortLength = length / 1024f;
            if (shortLength >= 1024) {
                shortLength = shortLength / 1024f;
                if (shortLength >= 1024) {
                    shortLength = shortLength / 1024f;
                    return String.format("%.2fGB", shortLength);
                } else
                    return String.format("%.2fMB", shortLength);
            } else
                return String.format("%.2fKB", shortLength);
        } else
            return length + "B";
    }

    public static double toMB(long length) {
        return length / 1024f / 1024f;
    }

    public static double toGB(long length) {
        return length / 1024f / 1024f / 1024f;
    }

    /**
     * 将传递过来的bitmap图片进行压缩保存
     *
     * @param isPrivatePath 存储的路径是否是私有路径，私有目录可以直接用File操作
     *                      为false存放的是公共目录，则picPath直接传文件名称即可
     */
    public static String saveTempBitmap(Context context, Bitmap bm, String picPath, boolean isPrivatePath) {
        if (isBelow29() || isPrivatePath) {
            try {
                if (picPath.lastIndexOf('/') > 0) {
                    File root = new File(picPath.substring(0, picPath.lastIndexOf('/')));
                    if (!root.exists())
                        root.mkdirs();
                }
                File f = new File(picPath);
                if (f.exists())
                    f.delete();
                FileOutputStream out = new FileOutputStream(f);
                bm.compress(Bitmap.CompressFormat.JPEG, NORMAL_QUALITY, out);
                out.flush();
                out.close();
                return picPath;
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            try {
                Uri downloadPicUri = getDownloadPicUri(context, picPath);
                if (downloadPicUri != null) {
                    OutputStream out = context.getContentResolver().openOutputStream(downloadPicUri);
                    if (out != null) {
                        bm.compress(Bitmap.CompressFormat.JPEG, NORMAL_QUALITY, out);
                        out.flush();
                        out.close();
                        return getFilePathByUri(context, downloadPicUri);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    //得到输入流字节大小(可用于计算网络文件字节大小)
    public static byte[] getInputStreamByte(InputStream inputStream) {
        byte[] b = new byte[1024];
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        int len;
        try {
            while ((len = inputStream.read(b)) != -1) {
                byteArrayOutputStream.write(b, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                byteArrayOutputStream.close();
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return byteArrayOutputStream.toByteArray();
    }

    // 获取文件的字节数据
    public static byte[] getFileByteArray(Context context, String filePath) {
        InputStream inputStream = getInputStream(context, filePath);
        if (inputStream != null)
            return getInputStreamByte(inputStream);
        return null;
    }

    /**
     * 按偏移量及需要读取的大小获取字节数据
     *
     * @param filePath  文件路径
     * @param offset    已经读取的偏移量
     * @param blockSize 需要读取的块大小
     * @return 该文件块的字节数据
     */
    public static byte[] getFileByBlockSize(Context context, String filePath, long offset, int blockSize) {
        InputStream inputStream = getInputStream(context, filePath);
        long fileLength = getFileLength(filePath);
        if (inputStream != null) {
            try {
                int curBlockSize; //当前需要读取的块大小
                byte[] result;
                if (fileLength == offset) { //因为offset已经是文件大小了，所以返回null代表读取完毕了
                    return null;
                } else if (fileLength >= offset + blockSize) {
                    curBlockSize = blockSize;
                    result = new byte[blockSize];
                } else {
                    curBlockSize = (int) (fileLength - offset);
                    result = new byte[curBlockSize];
                }
                byte[] readByte;
                if (curBlockSize >= 2048)
                    readByte = new byte[2048];
                else
                    readByte = new byte[curBlockSize];
                if (offset > 0)
                    inputStream.skip(offset);
                int readSize;
                int count = 0;
                while ((readSize = inputStream.read(readByte)) != -1 && curBlockSize - readSize >= 0) {
                    System.arraycopy(readByte, 0, result, count * 2048, readSize);
                    count++;
                    curBlockSize -= readSize;
                    if (curBlockSize < 2048)
                        readByte = new byte[curBlockSize];
                    if (curBlockSize == 0)
                        break;
                }
                return result;
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    //得到文件的后缀名并将其转换为小写(不包含'.')
    public static String getFileExtension(String url) {
        if (!TextUtils.isEmpty(url)) {
            url = url.replace("\\", "/");
            int fragment = url.lastIndexOf('#');
            if (fragment > 0) {
                url = url.substring(0, fragment);
            }

            int query = url.lastIndexOf('?');
            if (query > 0) {
                url = url.substring(0, query);
            }

            int filenamePos = url.lastIndexOf('/');
            String filename = 0 <= filenamePos ? url.substring(filenamePos + 1) : url;
            if (!filename.isEmpty()) {
                int dotPos = filename.lastIndexOf('.');
                if (0 <= dotPos) {
                    return filename.substring(dotPos + 1).toLowerCase();
                }
            }
        }
        return "";
    }

    // 生存图片文件名
    public static String getPhotoFileName() {
        return NumberUtils.GenerateGUID() + ".jpg";
    }

    // 生存图片文件名
    public static String getVideoFileName() {
        return NumberUtils.GenerateGUID() + ".mp4";
    }

    // 获取音视频时长,单位：ms
    public static long getVideoDuration(Context context, String path) {
        Uri fileUri = getFileUri(context, path);
        if (fileUri != null) {
            MediaMetadataRetriever mmr = null;
            try {
                mmr = new MediaMetadataRetriever();
                mmr.setDataSource(context, fileUri);
                String str = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
                if (str != null)
                    return Long.parseLong(str);
                else
                    return 0;
            } catch (Exception ignored) {
            } finally {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    try {
                        if (mmr != null)
                            mmr.close();
                    } catch (Exception ignored) {
                    }
                }
            }
        }
        return 0;
    }

    // 获取视频宽高
    public static int[] getVideoWidthHeight(Context context, String path) {
        int[] widthHeight = new int[2];
        MediaMetadataRetriever mmr = null;
        try {
            mmr = new MediaMetadataRetriever();
            mmr.setDataSource(context, getFileUri(context, path));
            widthHeight[0] = Integer.parseInt(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));
            widthHeight[1] = Integer.parseInt(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT));
        } catch (Exception ignored) {
        } finally {
            if (mmr != null) {
                try {
                    mmr.release();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return widthHeight;
    }

    // region 私有方法
    private static Uri getFileUriBelow29(Context context, String path) {
        File file = new File(path);
        if (Build.VERSION.SDK_INT >= 24) {
            return FileProvider.getUriForFile(context.getApplicationContext(), getFileProvider(context), file);
        } else {
            return Uri.fromFile(file);
        }
    }

    private static boolean isLocalStorageDocument(Context cxt, Uri uri) {
        String authority = uri.getAuthority();
        String fileProvider = getFileProvider(cxt);
        return getFileProvider(cxt).equals(uri.getAuthority());
    }

    private static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
    }

    private static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }

    private static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }

    /**
     * 获取FileProvider path
     */
    private static String getFilePathByFileProviderUri(Context context, Uri uri) {
        try {
            Class<FileProvider> fileProviderClass = FileProvider.class;
            Method getPathStrategy = fileProviderClass.getDeclaredMethod("getPathStrategy", Context.class, String.class);
            getPathStrategy.setAccessible(true);
            Object invoke = getPathStrategy.invoke(null, context, uri.getAuthority());
            if (invoke != null) {
                String PathStrategyStringClass = FileProvider.class.getName() + "$PathStrategy";
                Class<?> PathStrategy = Class.forName(PathStrategyStringClass);
                Method getFileForUri = PathStrategy.getDeclaredMethod("getFileForUri", Uri.class);
                getFileForUri.setAccessible(true);
                Object invoke1 = getFileForUri.invoke(invoke, uri);
                if (invoke1 instanceof File) {
                    return ((File) invoke1).getAbsolutePath();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Get the value of the data column for this Uri. This is useful for
     * MediaStore Uris, and other file-based ContentProviders.
     *
     * @param context       The context.
     * @param uri           The Uri to query.
     * @param selection     (Optional) Filter used in the query.
     * @param selectionArgs (Optional) Selection arguments used in the query.
     * @return The value of the _data column, which is typically a file path.
     */
    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
        String column = "_data";
        String[] projection = {column};
        try (Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null)) {
            if (cursor != null && cursor.moveToFirst()) {
                int column_index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(column_index);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    // endregion

    //由Uri读取路径
    public static String getFilePathByUri(Context context, Uri uri) {
        if (context == null || uri == null) return null;
        String filePath = getDataColumn(context, uri, null, null);
        if (!TextUtils.isEmpty(filePath))
            return filePath;

        try {
            if (isLocalStorageDocument(context, uri)) {
                // The path is the id
                filePath = getFilePathByFileProviderUri(context, uri);
            } else if (DocumentsContract.isDocumentUri(context, uri)) { // DocumentProvider
                // ExternalStorageProvider
                if (isExternalStorageDocument(uri)) {
                    String docId = DocumentsContract.getDocumentId(uri);
                    String[] split = docId.split(":");
                    String type = split[0];

                    if ("primary".equalsIgnoreCase(type)) {
                        filePath = Environment.getExternalStorageDirectory() + "/" + split[1];
                    } else if ("home".equalsIgnoreCase(type)) {
                        filePath = Environment.getExternalStorageDirectory() + "/" + split[1];
                    }
                } else if (isDownloadsDocument(uri)) { // DownloadsProvider
                    String id = DocumentsContract.getDocumentId(uri);
                    if (id.startsWith("raw:")) {
                        filePath = id.replaceFirst("raw:", "");
                    } else {
                        String[] split = id.split(":");
                        if (split.length == 2)
                            id = split[1];
                        Uri contentUri = ContentUris.withAppendedId(
                                Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));

                        filePath = getDataColumn(context, contentUri, null, null);
                    }
                } else if (isMediaDocument(uri)) { // MediaProvider
                    String docId = DocumentsContract.getDocumentId(uri);
                    String[] split = docId.split(":");
                    String type = split[0];

                    Uri contentUri = null;
                    if ("image".equals(type)) {
                        contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                    } else if ("video".equals(type)) {
                        contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                    } else if ("audio".equals(type)) {
                        contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                    } else {
                        try {
                            // content://com.android.providers.media.documents/document/document%3A1000002873
                            // /storage/emulated/0/com.supperrabbit.pdf/超级兔子PDF/qq/超级兔子PDF/PDF_图片合并 (1).pdf
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                                contentUri = MediaStore.getMediaUri(context, uri);
                                filePath = getDataColumn(context, contentUri, null, null);
                            }
                        } catch (Exception ignored) {
                        }
                        try {
                            if (TextUtils.isEmpty(filePath) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                                contentUri = MediaStore.getDocumentUri(context, uri);
                                filePath = getDataColumn(context, contentUri, null, null);
                            }
                        } catch (Exception ignored) {
                        }
                        if (TextUtils.isEmpty(filePath))
                            contentUri = MediaStore.Files.getContentUri("external");
                    }
                    if (TextUtils.isEmpty(filePath)) {
                        String selection = "_id=?";
                        String[] selectionArgs = new String[]{split[1]};

                        filePath = getDataColumn(context, contentUri, selection, selectionArgs);
                    }
                }
            } else if ("content".equalsIgnoreCase(uri.getScheme())) { // MediaStore (and general)
                filePath = getDataColumn(context, uri, null, null);
            } else if ("file".equalsIgnoreCase(uri.getScheme())) { // File
                filePath = uri.getPath();
            }
        } catch (Exception ignored) {
        }
        if (TextUtils.isEmpty(filePath) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
            filePath = uriToFileApiQ(context, uri);
        if (!TextUtils.isEmpty(filePath)) {
            String dirPath = filePath;
            if (filePath.contains("/")) {
                dirPath = filePath.substring(0, filePath.lastIndexOf("/"));
            }
            // 创建文件夹
            new File(dirPath).mkdirs();
        }
        return filePath;
    }

    /**
     * Android 10 以上适配 :
     * content://com.android.providers.media.documents/document/document%3A98
     * 例如以上uri，通过正常方式读取不到path，则先拷贝到私有目录，之后返回路径
     * 注：需要删除拷贝文件
     */
    @RequiresApi(api = Build.VERSION_CODES.Q)
    private static String uriToFileApiQ(Context context, Uri uri) {
        if (uri.getScheme() == null) return null;
        File file = null;
        //android10以上转换
        if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {
            if (uri.getPath() == null)
                return null;
            file = new File(uri.getPath());
        } else if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
            //把文件复制到沙盒目录
            ContentResolver contentResolver = context.getContentResolver();
            Cursor cursor = contentResolver.query(uri, null, null, null, null);
            if (cursor != null) {
                if (cursor.moveToFirst()) {
                    @SuppressLint("Range") String displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
                    try {
                        InputStream is = contentResolver.openInputStream(uri);
                        if (is != null) {
                            // 大于500M的文件不进行操作
                            if (is.available() < 500 * 1024 * 1024) {
                                File cache = new File(getAppCachePath(context, "select_file"), displayName);
                                if (cache.exists())
                                    cache.delete();
                                FileOutputStream fos = new FileOutputStream(cache);
                                android.os.FileUtils.copy(is, fos);
                                file = cache;
                                fos.close();
                            } else {
                                ToastUtils.showShort(context, R.string.base_please_choose_file_size_below_500mb);
                            }
                            is.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                cursor.close();
            }
        }
        if (file == null)
            return null;
        else
            return file.getAbsolutePath();
    }

    //获取公共文件对应的Uri
    public static Uri getFileUri(Context context, String path) {
        if (context == null || TextUtils.isEmpty(path))
            return null;

        //Android10以下需要有读权限才能进行操作ContentResolver.query
        if (context instanceof FragmentActivity && PermissionUtils.requestStoragePermission((FragmentActivity) context, isAllGranted -> {
        }))
            return null;

        Uri uri = null;
        if (isBelow29()) {
            uri = getFileUriBelow29(context, path);
        } else {
            Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    new String[]{MediaStore.Images.Media._ID}, MediaStore.Images.Media.DATA + "=? ",
                    new String[]{path}, null);
            if (cursor != null && cursor.moveToFirst()) {
                String id = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID));
                uri = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
            }
            if (uri == null) {
                cursor = context.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
                        new String[]{MediaStore.Video.Media._ID}, MediaStore.Video.Media.DATA + "=? ",
                        new String[]{path}, null);
                if (cursor != null && cursor.moveToFirst()) {
                    String id = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID));
                    uri = Uri.withAppendedPath(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);
                }
            }
            if (uri == null) {
                cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                        new String[]{MediaStore.Audio.Media._ID}, MediaStore.Audio.Media.DATA + "=? ",
                        new String[]{path}, null);
                if (cursor != null && cursor.moveToFirst()) {
                    String id = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));
                    uri = Uri.withAppendedPath(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);
                }
            }
            if (uri == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                String fileName = path;
                if (path.contains("/"))
                    fileName = path.substring(path.lastIndexOf("/") + 1);
                if (path.contains("\\"))
                    fileName = path.substring(path.lastIndexOf("\\") + 1);
                cursor = context.getContentResolver().query(MediaStore.Downloads.EXTERNAL_CONTENT_URI,
                        new String[]{MediaStore.Downloads._ID}, MediaStore.Downloads.DISPLAY_NAME + "=? ",
                        new String[]{fileName}, null);
                if (cursor != null && cursor.moveToFirst()) {
                    String id = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Downloads._ID));
                    uri = Uri.withAppendedPath(MediaStore.Downloads.EXTERNAL_CONTENT_URI, id);
                }
            }
            try {
                if (cursor != null)
                    cursor.close();
            } catch (Exception ignored) {
            }
            // 私有目录下的文件还是通过旧的方式获取
            if (uri == null) uri = getFileUriBelow29(context, path);
        }
        return uri;
    }

    public static InputStream getInputStream(Context context, String filePath) {
        if (context == null || TextUtils.isEmpty(filePath)) return null;
        if (isBelow29()) {
            try {
                return new FileInputStream(filePath);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else { //android10以上
            Uri uri = getFileUri(context, filePath);
            if (uri != null)
                try {
                    return context.getContentResolver().openInputStream(uri);
                } catch (Exception e) {
                    e.printStackTrace();
                }
        }
        return null;
    }

    public static InputStream getInputStream(Context context, Uri uri) {
        if (context == null || uri == null) return null;
        if (isBelow29()) {
            try {
                return new FileInputStream(getFilePathByUri(context, uri));
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else { //android10以上
            try {
                return context.getContentResolver().openInputStream(uri);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public static InputStream getInputStream(Context context, Uri uri, String filePath) {
        InputStream inputStream = getInputStream(context, uri);
        if (inputStream == null)
            inputStream = getInputStream(context, filePath);
        return inputStream;
    }

    public static OutputStream getOutputStream(Context context, String filePath) {
        if (TextUtils.isEmpty(filePath)) return null;
        if (isBelow29()) {
            try {
                return new FileOutputStream(filePath);
            } catch (Exception e) {
                if (e.getMessage() != null && e.getMessage().contains("No space left on device"))
                    ToastUtils.showShort(context, R.string.base_memory_is_not_left_please_clear_and_retry);
                else
                    ToastUtils.showShort(context, R.string.base_file_output_error);
                return null;
            }
        } else { //android10以上
            Uri uri = getFileUri(context, filePath);
            if (uri != null)
                try {
                    return context.getContentResolver().openOutputStream(uri);
                } catch (Exception e) {
                    e.printStackTrace();
                    if (e.getMessage() != null && e.getMessage().contains("No space left on device"))
                        ToastUtils.showShort(context, R.string.base_memory_is_not_left_please_clear_and_retry);
                    else
                        ToastUtils.showShort(context, R.string.base_file_output_error);
                }
            return null;
        }
    }

    public static OutputStream getOutputStream(Context context, Uri uri) {
        if (isBelow29()) {
            try {
                return new FileOutputStream(getFilePathByUri(context, uri));
            } catch (FileNotFoundException e) {
                return null;
            }
        } else { //android10以上
            if (uri != null)
                try {
                    return context.getContentResolver().openOutputStream(uri);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            return null;
        }
    }

    /**
     * 获取对应的可操作路径
     * 通过路径进行判断是否是私有目录，私有目录则可以直接使用，公共目录则需要复制文件到私有目录，之后才能对路径文件操作
     */
    public static String getOperationalFilePath(Context context, String path) {
        Uri uri = getFileUri(context, path);
        if (uri == null) return "";
        if (isLocalStorageDocument(context, uri)) {
            return path;
        } else {
            InputStream is = getInputStream(context, path);
            if (is != null) {
                FileOutputStream fos = null;
                String savePath = getAppCachePath(context, "temp") + "temp_" + NumberUtils.GenerateGUID()
                        + path.substring(path.lastIndexOf("."));
                try {
                    fos = new FileOutputStream(savePath);
                    if (!isBelow29()) { //android10以上
                        android.os.FileUtils.copy(is, fos);
                    } else {
                        byte[] bytes = new byte[2048];
                        while (is.read(bytes) != -1) {
                            fos.write(bytes);
                        }
                        fos.flush();
                    }
                } catch (IOException ignored) {
                } finally {
                    try {
                        is.close();
                        if (fos != null)
                            fos.close();
                    } catch (IOException ignored) {
                    }
                }
                return savePath;
            }
        }
        return path;
    }

    public static void copyFile(Context context, Uri uri, String path, String savePath, IOnSaveFileListener listener) {
        if (context == null) return;
        ThreadPoolUtils.getInstance().execute(new ComparableRunnable() {
            @Override
            public void run() {
                InputStream is = getInputStream(context, uri, path);
                if (is != null) {
                    // 如果文件名存在空格，会导致复制虽然显示成功，但没有生成文件
                    String savePathFinal = savePath.replace(" ", "");
                    OutputStream fos = getOutputStream(context, savePathFinal);
                    if (fos != null) {
                        try {
                            if (!isBelow29()) { //android10以上
                                android.os.FileUtils.copy(is, fos);
                            } else {
                                byte[] bytes = new byte[2048];
                                while (is.read(bytes) != -1) {
                                    fos.write(bytes);
                                }
                                fos.flush();
                            }
                            ThreadPoolUtils.getInstance().executeOnMainThread(() -> {
                                if (listener != null)
                                    listener.onSaveResult(savePathFinal);
                            });
                        } catch (IOException e) {
                            if (e.getMessage() != null && e.getMessage().contains("No space left on device")) {
                                ToastUtils.showShort(context, R.string.base_memory_is_not_left_please_clear_and_retry);
                            } else {
                                ToastUtils.showShort(context, R.string.base_file_copy_error);
                            }
                            ThreadPoolUtils.getInstance().executeOnMainThread(() -> {
                                if (listener != null)
                                    listener.onSaveResult(null);
                            });
                        } finally {
                            try {
                                is.close();
                                fos.close();
                            } catch (IOException ignored) {
                            }
                        }
                    } else {
                        ThreadPoolUtils.getInstance().executeOnMainThread(() -> {
                            if (listener != null)
                                listener.onSaveResult(null);
                        });
                    }
                } else {
                    ThreadPoolUtils.getInstance().executeOnMainThread(() -> {
                        if (listener != null)
                            listener.onSaveResult(null);
                    });
                    ToastUtils.showShort(context, R.string.base_file_read_fail_no_permission);
                }
            }
        });
    }

    /**
     * 重命名文件：
     * oldPath 和 newPath必须是新旧文件的绝对路径
     */
    public static boolean renameFile(String oldPath, String newPath) {
        if (TextUtils.isEmpty(oldPath)) {
            return false;
        }

        if (TextUtils.isEmpty(newPath)) {
            return false;
        }
        File oldFile = new File(oldPath);
        File newFile = new File(newPath);
        if (newFile.exists()) {
            return false;
        }
        //重命名
        return oldFile.renameTo(newFile);
    }

    // 保存视图View到系统相册
    public static void saveViewToPicFile(Context context, View v, IOnSaveFileListener listener) {
        ThreadPoolUtils.getInstance().execute(new ComparableRunnable() {
            @Override
            public void run() {
                Bitmap bitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
                Canvas c = new Canvas(bitmap);
                v.draw(c);

                Uri picUri = getDownloadPicUri(context, System.currentTimeMillis() + ".png");
                OutputStream out = null;
                String filePathByUri;
                try {
                    filePathByUri = getFilePathByUri(context, picUri);
                    out = getOutputStream(context, filePathByUri);
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
                    FileUtils.updateGallery(context, filePathByUri);
                } catch (Exception e) {
                    e.printStackTrace();
                    filePathByUri = null;
                } finally {
                    try {
                        if (out != null) {
                            out.flush();
                            out.close();
                        }
                    } catch (Exception ignored) {
                    }
                }
                if (listener != null)
                    listener.onSaveResult(filePathByUri);
            }
        });
    }

    public interface IOnSaveFileListener {
        void onSaveResult(String filePath);
    }

    /**
     * 将图片转换成Base64编码的字符串
     */
    public static String imageToBase64(String path) {
        if (TextUtils.isEmpty(path)) {
            return null;
        }
        InputStream is = null;
        byte[] data;
        String result = null;
        try {
            is = new FileInputStream(path);
            //创建一个字符流大小的数组。
            data = new byte[is.available()];
            //写入数组
            is.read(data);
            //用默认的编码格式进行编码
            result = Base64.encodeToString(data, Base64.NO_CLOSE);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
        return result;
    }

    public static String imageToBase64(Context context, String path, int quality) {
        if (context == null) return null;
        if (!FileUtils.exists(context, path)) return null;
        byte[] bytes = getImageBytes(context, path, quality);
        if (bytes == null)
            return "";
        return Base64.encodeToString(bytes, Base64.NO_CLOSE);
    }

    public static byte[] getImageBytes(Context context, String path, int quality) {
        if (context == null) return null;
        byte[] bytes = null;
        int[] originalSize = BitmapUtil.getPhotoSize(context, path);
        int[] ruleSize = calculateSizeForUploadPic(originalSize[0], originalSize[1]);
        // 按ruleSize进行压缩
        Bitmap bm = BitmapUtil.getBitmapWithSize(context, path, ruleSize[0]);
        if (bm != null) {
            int degree = BitmapUtil.readPictureDegree(context, path);
            if (degree != 0) { //有些图片本身存在选择角度，需要进行相应旋转
                Bitmap resizedBitmap = BitmapUtil.rotate(bm, degree);
                bytes = BitmapUtil.bitmapToByte(resizedBitmap, quality);
                resizedBitmap.recycle();
            } else {
                bytes = BitmapUtil.bitmapToByte(bm, quality);
            }
            bm.recycle();
        }
        return bytes;
    }

    // 计算上传的图片尺寸，根据指定的最大限定返回服务器需要的尺寸大小
    private static int[] calculateSizeForUploadPic(int width, int height) {
        if (width == 0 || height == 0) return new int[]{width, height};
        int maxValue = 1280;//指定的最大值
        int ration = 2;//指定的分辨率

        float whDirRation = width / (float) height;
        float hwDirRation = height / (float) width;
        float newWidth, newHeight;

        //=========calculate=========//
        //1、宽高都小于等于指定的最大值 【原尺寸输出】
        if (width <= maxValue && height <= maxValue) {
            newWidth = width;
            newHeight = height;
        }
        //2、宽高有任意一边大于指定的最大值
        else {
            //2.1、宽高比小于等于指定的分辨率 【取宽高较大的一边设为指定的最大值，另一边等比率缩放】
            if (whDirRation <= ration && hwDirRation <= ration) {
                if (height > width) {
                    newHeight = maxValue;
                    newWidth = whDirRation * maxValue;
                } else {
                    newWidth = maxValue;
                    newHeight = hwDirRation * maxValue;
                }
            }
            //2.2、图片宽高比或者高宽比大于指定的分辨率
            else {
                //2.2.1、图片都大于指定的最大值 【取宽高较小的一边设为指定的最大值，另一边等比率缩放】
                if (width > maxValue && height > maxValue) {
                    if (width > height) {
                        newHeight = maxValue;
                        newWidth = whDirRation * maxValue;
                    } else {
                        newWidth = maxValue;
                        newHeight = hwDirRation * maxValue;
                    }
                }
                //2.2.2、宽高一边大于指定的最大值，一边小于指定的最大值.【原尺寸输出】
                else {
                    newWidth = width;
                    newHeight = height;
                }
            }
        }
        return new int[]{(int) newWidth, (int) newHeight};
    }

    public static String getFileName(Context context, Uri uri) {
        if (context == null || uri == null) return null;
        String mimeType = context.getContentResolver().getType(uri);
        String filename = null;
        if (mimeType == null) {
            String path = getFilePathByUri(context, uri);
            if (path == null) {
                filename = getName(uri.toString());
            } else {
                File file = new File(path);
                filename = file.getName();
            }
        } else {
            Cursor returnCursor = context.getContentResolver().query(uri, null,
                    null, null, null);
            if (returnCursor != null) {
                int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                returnCursor.moveToFirst();
                filename = returnCursor.getString(nameIndex);
                returnCursor.close();
            }
        }
        return filename;
    }

    private static String getName(String filename) {
        if (filename == null) {
            return null;
        }
        int index = filename.lastIndexOf('/');
        return filename.substring(index + 1);
    }

    /**
     * 将信息保存到本地
     */
    public static void save2ExternalFile(Context context, String fileName, String info) {
        ThreadPoolUtils.getInstance().execute(new ComparableRunnable() {
            @Override
            public void run() {
                String message = TimeUtils.getCurrentDateTime() + '\t' + info + '\n';
                FileOutputStream fos = null;
                try {
                    File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), fileName);
                    fos = new FileOutputStream(file, true);
                    fos.write(message.getBytes());
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (fos != null)
                            fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }
}